package com.crazymo.binderpool;

/******************************************************************
 * @Copyright : (C), 2001-2021, ZHEJIANG DAHUA TECHNOLOGY CO.,LTD
 * @FileName : BinderPool
 * @Author : 224967  Crazy.Mo
 * @Date : 2022/2/11 16:20
 * @Description :    
 * @History :
 * <author>  <time>  <version>   <desc>
 * 224967    修改时间    版本号       描述
 ******************************************************************/

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;

/**
 * 连接池的具体实现，首先在其内部它要去绑定远程服务，绑定成功后就可以 通过它的queryBinder方法获取对应的Binder了
 */
public final class BinderPool {
    public final static int SECURITY_CODE=100;
    public final static int COMPUTE_CODE=101;
    private Context mContext;
    private IBinderPool mIBinderPool;
    private static volatile BinderPool instance;
    private CountDownLatch mCountDownLatch;
    private ConcurrentHashMap<Integer,IBinder> binderObjMap;

    private final IBinder.DeathRecipient mRecipient=new IBinder.DeathRecipient() {
        @Override
        public void binderDied() {
            mIBinderPool.asBinder().unlinkToDeath(mRecipient,0);
            binderObjMap.clear();
            mIBinderPool=null;
            connectBinderPoolService();
        }
    };
    private final ServiceConnection mConnection=new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.d("TAG","BinderPool#onServiceConnected in"+Thread.currentThread().getName());
            mIBinderPool=IBinderPool.Stub.asInterface(service);
            try{
                mIBinderPool.asBinder().linkToDeath(mRecipient,0);
            }catch (RemoteException e){
                e.printStackTrace();
            }finally {
                mCountDownLatch.countDown();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };

    private BinderPool(Context context){
        Log.d("TAG","BinderPool#");
        mContext=context.getApplicationContext();
        connectBinderPoolService();
        binderObjMap=new ConcurrentHashMap<>(16);
    }

    public static BinderPool getInstance(Context context){
        synchronized (BinderPool.class) {
            if (instance == null) {
                instance = new BinderPool(context);
            }
        }
        return instance;
    }

    private synchronized void connectBinderPoolService() {
        /**
         * 通过CountdownLatch 使得BinderService操作由异步变成了同步操作，意味着当它耗时时不宜放在主线程去执行，一般Binder也是耗时的也不宜放在主线程执行
         */
        mCountDownLatch=new CountDownLatch(1);
        Intent intent=new Intent(mContext,BinderPoolService.class);
        mContext.bindService(intent,mConnection,Context.BIND_AUTO_CREATE);
        Log.d("TAG","BinderPool#connectBinderPoolService in"+Thread.currentThread().getName());
        try{
            mCountDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public IBinder queryBinder(int binderCode){
        IBinder iBinder=null;
        try{
            Log.d("TAG","BinderPool#queryBinder code="+binderCode);
            if(mIBinderPool!=null){
                if (binderObjMap.isEmpty()){
                    iBinder = mIBinderPool.queryBinder(binderCode);
                    binderObjMap.put(binderCode,iBinder);
                }else{
                    if (binderObjMap.containsKey(binderCode)){
                        iBinder=binderObjMap.get(binderCode);
                    }else{
                        iBinder = mIBinderPool.queryBinder(binderCode);
                    }
                }
            }
        }catch (RemoteException e){
            e.printStackTrace();
        }
        return iBinder;
    }
}
